#include "Rp2Particles.h"
#include "Rp2Culler.h"
#include "Rp2Light.h"
#include "Rp2Camera.h"

using namespace Rp2;

//---------------------------------------------------------------------------------------------------
Particles::Particles()
{
	;
}
//---------------------------------------------------------------------------------------------------
Particles::Particles(const Attributes& rkAttr, Vector3fArray* pkLocations,
		FloatArray* pkSizes)
	:
	Locations(pkLocations),
	Sizes(pkSizes)
{
    // Create storage for model space quad vertices.
    int iLQuantity = Locations->GetQuantity();
    int iVQuantity = 4*iLQuantity;
	VBuffer = new VertexBuffer(rkAttr, iVQuantity);

	// set 2D texture coordinates to the standard ones
	if (rkAttr.HasTCoord(0) && rkAttr.GetTCoordChannels(0) == 2)
	{
		for (int i = 0, j = 0; i < iLQuantity; i++)
		{
			VBuffer->TCoord2(0,j++) = Vector2f(0.0f, 0.0f);
			VBuffer->TCoord2(0,j++) = Vector2f(1.0f, 0.0f);
			VBuffer->TCoord2(0,j++) = Vector2f(1.0f, 1.0f);
			VBuffer->TCoord2(0,j++) = Vector2f(0.0f, 1.0f);
		}
	}

	// generate index buffer
	int iIQuantity = 6 * iLQuantity;
	IBuffer = new IndexBuffer(iIQuantity);
	int* aiIndex = IBuffer->GetData();
	for (int i = 0, j = 0; i < iLQuantity; i++)
	{
		int iP0 = 4 * i, iP1 = iP0 + 1, iP2 = iP0 + 2, iP3 = iP0 + 3;
		aiIndex[j++] = iP0;
		aiIndex[j++] = iP1;
		aiIndex[j++] = iP2;
		aiIndex[j++] = iP0;
		aiIndex[j++] = iP2;
		aiIndex[j++] = iP3;
	}

	// compute a bounding sphere base on locations
	ModelBound->ComputeFromData(Locations);

	SizeAdjust = 1.0f;
	m_iActiveQuantity = iLQuantity;
}
//---------------------------------------------------------------------------------------------------
Particles::~Particles()
{
}
//---------------------------------------------------------------------------------------------------
void Particles::SetActiveQuantity(int iActiveQuantity)
{
	int iLQuantity = Locations->GetQuantity();
	if (0 <= iActiveQuantity && iActiveQuantity <= iLQuantity)
	{
		m_iActiveQuantity = iActiveQuantity;
	}
	else
	{
		m_iActiveQuantity = iLQuantity;
	}

	IBuffer->SetIndexQuantity(6 * m_iActiveQuantity);
	
	VBuffer->SetVertexQuantity(4 * m_iActiveQuantity);
}
//---------------------------------------------------------------------------------------------------
void Particles::GenerateParticles(const Camera* pkCamera)
{
    // Get camera axis directions in model space of particles.
	Vector3f kUpR = (pkCamera->GetUVector() + pkCamera->GetRVector()) * 
		World.GetRotate();
	Vector3f kUmR = (pkCamera->GetUVector() - pkCamera->GetRVector()) *
		World.GetRotate();

	// normal vectors are always towards the viewer
	if (VBuffer->GetAttributes().HasNormal())
	{
		Vector3f kDir = -pkCamera->GetDVector() * World.GetRotate();
		for (int i = 0; i < 4 * m_iActiveQuantity; i++)
		{
			VBuffer->Normal3(i) = kDir;
		}
	}

	// generate particle quadrilaterals as pairs of triangles.
	Vector3f* akLocation = Locations->GetData();
	float* afSizes = Sizes->GetData();
	for (int i= 0, j = 0; i < m_iActiveQuantity; i++)
	{
		Vector3f rkCenter = akLocation[i];
		
		float fTrueSize = SizeAdjust * afSizes[i];
		Vector3f kScaledUpR = fTrueSize * kUpR;
		Vector3f kScaledUmR = fTrueSize * kUmR;

		VBuffer->Position3(j++) = rkCenter - kScaledUpR;
		VBuffer->Position3(j++) = rkCenter - kScaledUmR;
		VBuffer->Position3(j++) = rkCenter + kScaledUpR;
		VBuffer->Position3(j++) = rkCenter + kScaledUmR;
	}

	UpdateMS(true);

}
//---------------------------------------------------------------------------------------------------
void Particles::GetVisibleSet(Culler& rkCuller, bool bNoCull)
{
	GenerateParticles(rkCuller.GetCamera());
	TriMesh::GetVisibleSet(rkCuller, bNoCull);
}
//---------------------------------------------------------------------------------------------------